package streaming.test.session_transmission;

import java.io.IOException;
import java.net.InetAddress;

import javax.media.Format;
import javax.media.Manager;
import javax.media.Processor;
import javax.media.ProcessorModel;
import javax.media.protocol.ContentDescriptor;
import javax.media.rtp.RemoteListener;
import javax.media.rtp.SendStream;
import javax.media.rtp.SendStreamListener;
import javax.media.rtp.SessionAddress;
import javax.media.rtp.SessionListener;
import javax.media.rtp.event.RemoteEvent;
import javax.media.rtp.event.SendStreamEvent;
import javax.media.rtp.event.SessionEvent;
import javax.media.rtp.rtcp.SourceDescription;

import utils.NetworkUtils;

import com.sun.media.rtp.RTPSessionMgr;

public class Transmiter  implements StreamManager, SendStreamListener, RemoteListener, SessionListener{

	
	
	private RTPSessionMgr manager;
	private SendStream stream;
	private Processor processor;
	
	private InetAddress destination;
	private int port;
	private int localPort;
	
	private Format format;
	
	private State state;
	
	public Transmiter(InetAddress destination, int port, int localPort, Format format) {
		this.destination = destination;
		this.format = format;
		state = State.NEW;
		initializeProcessor();
	}
	
	public Transmiter(Format format) {
		this.format = format;
		state = State.NEW;
		initializeProcessor();
	}
	
	public void initializeProcessor(){
		ProcessorModel model = new ProcessorModel(
				new Format[]{format},
				new ContentDescriptor(ContentDescriptor.RAW_RTP));
		
		try {
			processor = Manager.createRealizedProcessor(model);
		} catch (Exception e) {
			// TODO remove
			e.printStackTrace();
			System.out.println("Processor failed");
			state = State.FAILED;
		}
	}
	
	public void initialize(){
		initialize(null, 0, 0);
	}
	
	public void initialize(InetAddress destination, int port, int localPort){
		if(destination != null){
			this.destination = destination;
			this.port = port;
			this.localPort = localPort;
		}
		if(this.destination == null || this.port == 0){
			state = State.FAILED;
			return;
		}
			
		
		if(state == State.FAILED) return;
		try {
			
			manager = new RTPSessionMgr();
			
			manager.addSendStreamListener(this);
			manager.addRemoteListener(this);
			manager.addSessionListener(this);
			
			String cname = manager.generateCNAME();
			SourceDescription[] userdesclist= new SourceDescription[]{
					new SourceDescription(SourceDescription
							.SOURCE_DESC_EMAIL,
							"jmf-user@sun.com",
							1,
							false),
					new SourceDescription(SourceDescription
							.SOURCE_DESC_CNAME,
							cname,
							1,
							false),
					new SourceDescription(SourceDescription
							.SOURCE_DESC_TOOL,
							"test multimedia streaminga",
							1,
							false)
            };
			
			SessionAddress s = new SessionAddress(NetworkUtils.getLocalAddress(), this.localPort);
			System.out.println(s);
			manager.initialize(s);
			manager.addTarget(new SessionAddress( destination, port));
			
			
			
			
			
			stream = manager.createSendStream(processor.getDataOutput(), 0);
			state = State.INITIALIZED;
			
		} catch (Exception e) {
			state = State.FAILED;
			// TODO remove
			e.printStackTrace();
		}
	}

	public State getState() {
		return state;
	}

	@Override
	public void update(SendStreamEvent e) {
		// TODO Auto-generated method stub
		System.out.println(e);
	}

	@Override
	public void update(RemoteEvent e) {
		// TODO Auto-generated method stub
		System.out.println(e);
	}

	@Override
	public void update(SessionEvent e) {
		// TODO Auto-generated method stub
		System.out.println(e);
	}

	@Override
	public void pause() {
		processor.stop();
		try {
			stream.stop();
			state = State.PAUSED;
		} catch (IOException e) {
			// TODO remove
			e.printStackTrace();
		}
	}

	@Override
	public void start() {
		processor.start();
		try {
			stream.start();
			state = State.IN_PROGRESS;
		} catch (IOException e) {
			// TODO remove
			e.printStackTrace();
		}
		
	}

	@Override
	public void stop() {
		processor.stop();
		try {
			stream.stop();
			stream.close();
			processor.deallocate();
			state = State.ENDED;
		} catch (IOException e) {
			// TODO remove
			e.printStackTrace();
		}
		
	}



	public InetAddress getDestination() {
		return destination;
	}



	public void setDestination(InetAddress destination) {
		this.destination = destination;
	}



	public int getPort() {
		return port;
	}



	public void setPort(int port) {
		this.port = port;
	}
	
}
